#include "calendar.h"
#include <QDebug>

Calendar::Calendar(QWidget *parent) : QWidget(parent)
{
    QFontDatabase fontDb;
    if(!fontDb.families().contains("FontAwesome"))
    {
        int fontId = fontDb.addApplicationFont(":/res/fontawesome-webfont.ttf");
        QStringList fontName = fontDb.applicationFontFamilies(fontId);
        if(fontName.count() == 0)
        {
            qDebug() << "load fail";
        }
        else
            qDebug() << fontName;
    }

    if(fontDb.families().contains("FontAwesome"))
    {
        iconFont = QFont("FontAwesome");
        iconFont.setHintingPreference(QFont::PreferNoHinting);
    }

    btnClick = false;

    calendarStyle = CalendarStyle_Red;
    weekNameFormat = WeekNameFormat_Short;
    date = QDate::currentDate();

    weekTextColor = QColor(255, 255, 255);
    weekBgColor = QColor(22, 160, 134);

    showLunar = true;
    bgImage = ":/res/bg_calendar.png";
    selectType = SelectType_Rect;

    borderColor = QColor(180, 180, 180);
    weekColor = QColor(255, 0, 0);
    superColor = QColor(255, 129, 6);
    lunarColor = QColor(55, 156, 238);

    currentTextColor = QColor(0, 0, 0);
    otherTextColor = QColor(200, 200, 200);
    selectTextColor = QColor(255, 255, 255);
    hoverTextColor = QColor(250, 250, 250);

    currentLunarColor = QColor(150, 150, 150);
    otherLunarColor = QColor(200, 200, 200);
    selectLunarColor = QColor(255, 255, 255);
    hoverLunarColor = QColor(250, 250, 250);

    currentBgColor = QColor(255, 255, 255);
    otherBgColor = QColor(240, 240, 240);
    selectBgColor = QColor(208, 47, 18);
    hoverBgColor = QColor(204, 183, 180);

    initWidget();
    initStyle();
    initDate();
}

void Calendar::initWidget()
{
    setObjectName("Calendar");

    QWidget *widgetTop = new QWidget();
    widgetTop->setMinimumHeight(35);

    QToolButton *btnPrevYear = new QToolButton;
    btnPrevYear->setFixedWidth(35);
    btnPrevYear->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    btnPrevYear->setFont(iconFont);
    btnPrevYear->setText(QChar(0xf060));

    QToolButton *btnNextYear = new QToolButton;
    btnNextYear->setFixedWidth(35);
    btnNextYear->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    btnNextYear->setFont(iconFont);
    btnNextYear->setText(QChar(0xf061));

    QToolButton *btnPreMonth = new QToolButton;
    btnPreMonth->setFixedWidth(35);
    btnPreMonth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
    btnPreMonth->setFont(iconFont);
    btnPreMonth->setText(QChar(0xf060));

    QToolButton *btnNextMonth = new QToolButton;
    btnNextMonth->setFixedWidth(35);
    btnNextMonth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
    btnNextMonth->setFont(iconFont);
    btnNextMonth->setText(QChar(0xf061));

    QPushButton *btnToday = new QPushButton;
    btnToday->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
    btnToday->setText("转到今天");

    cboxYear = new QComboBox;
    for(int i=1901; i<=2099; i++)
    {
        cboxYear->addItem(QString("%1年").arg(i));
    }

    cboxMonth = new QComboBox;
    for(int i=1; i<=12; i++)
        cboxMonth->addItem(QString("%1月").arg(i));

    QWidget *widgetBlank1 = new QWidget;
    widgetBlank1->setFixedWidth(5);
    QWidget *widgetBlank2 = new QWidget();
    widgetBlank2->setFixedWidth(5);

    QHBoxLayout *layoutTop = new QHBoxLayout(widgetTop);
    layoutTop->setContentsMargins(0, 0, 0, 9);
    layoutTop->addWidget(btnPrevYear);
    layoutTop->addWidget(cboxYear);
    layoutTop->addWidget(btnNextYear);
    layoutTop->addWidget(widgetBlank1);
    layoutTop->addWidget(btnPreMonth);
    layoutTop->addWidget(cboxMonth);
    layoutTop->addWidget(btnNextMonth);
    layoutTop->addWidget(widgetBlank2);
    layoutTop->addWidget(btnToday);

    QWidget *widgetWeek = new QWidget;
    widgetWeek->setMinimumHeight(30);

    QHBoxLayout *layoutWeek = new QHBoxLayout(widgetWeek);
    layoutWeek->setContentsMargins(0,0,0,0);
    layoutWeek->setSpacing(0);

    for(int i=0; i<7; i++)
    {
        QLabel *label = new QLabel;
        label->setAlignment(Qt::AlignCenter);
        layoutWeek->addWidget(label);
        labelWeeks.append(label);
    }

    setWeekNameFormat(WeekNameFormat_Long);

    QWidget *widgetBody = new QWidget;

    QGridLayout *layoutBody = new QGridLayout(widgetBody);
    layoutBody->setContentsMargins(1,1,1,1);
    layoutBody->setHorizontalSpacing(0);
    layoutBody->setVerticalSpacing(0);

    for(int i=0; i<42; i++)
    {
        CalendarItem *lab = new CalendarItem;
        connect(lab, SIGNAL(clicked(QDate, CalendarItem::DayType)), this, SLOT(clicked(QDate, CalendarItem::DayType)));
        layoutBody->addWidget(lab, i/7, i%7);
        dayItems.append(lab);
    }

    QVBoxLayout *verlayoutCalendar = new QVBoxLayout(this);
    verlayoutCalendar->setContentsMargins(0,0,0,0);
    verlayoutCalendar->setSpacing(0);
    verlayoutCalendar->addWidget(widgetTop);
    verlayoutCalendar->addWidget(widgetWeek);
    verlayoutCalendar->addWidget(widgetBody, 1);

    connect(btnPrevYear, SIGNAL(clicked(bool)), this, SLOT(showPreviousYear()));
    connect(btnNextYear, SIGNAL(clicked(bool)), this, SLOT(showNextYear()));
    connect(btnPreMonth, SIGNAL(clicked(bool)), this, SLOT(showPreviousMonth()));
    connect(btnNextMonth, SIGNAL(clicked(bool)), this, SLOT(showNextMonth()));
    connect(btnToday, SIGNAL(clicked(bool)), this, SLOT(showToday()));
    connect(cboxYear, SIGNAL(currentIndexChanged(QString)), this, SLOT(yearChanged(QString)));
    connect(cboxMonth, SIGNAL(currentIndexChanged(QString)), this, SLOT(monthChanges(QString)));
//    connect(cboxYear, &QComboBox::currentIndexChanged, this, &Calendar::yearChanged);
//    connect(cboxMonth, &QComboBox::currentIndexChanged, this, &Calendar::monthChanges);
}
/*
void Calendar::setWeekFormat(const Calendar::WeekNameFormat &weekNameFormat)
{
    if(this->weekNameFormat != weekNameFormat)
    {
        this->weekNameFormat = weekNameFormat;

        QStringList listWeek;
        if(weekNameFormat == WeekNameFormat_Short)
            listWeek << "日" << "一" << "二" << "三" << "四" << "五" << "六";
        else if(weekNameFormat == WeekNameFormat_Normal)
            listWeek << "周日" << "周一" << "周二" << "周三" << "周四" << "周五" << "周六";
        else if(weekNameFormat == WeekNameFormat_Long)
            listWeek << "星期天" << "星期一" << "星期二" << "星期三" << "星期四" << "星期五" << "星期六";
        else if(weekNameFormat == WeekNameFormat_En)
            listWeek << "Sun" << "Mon" << "Tue" << "Wed" << "Thu" << "Fri" << "Sat";

        for(int i=0; i<7; i++)
        {
            labelWeeks.at(i)->setText(listWeek.at(i));
        }
    }
}*/

void Calendar::initStyle()
{
    QStringList qss;

    qss.append(QString("QLabel{background:%1;color:%2}").arg(weekBgColor.name()).arg(weekTextColor.name()));

    qss.append(QString("QWidget#widgetBody{border:1px solid %1;}").arg(borderColor.name()));
    qss.append(QString("QToolButton{padding:0px;background:none;border:none;border-radius:5px;}"));
    qss.append(QString("QToolButton:hover{background:#16A085;color:#FFFFFF;}"));
    qss.append(QString("QPushButton{background:#16A085;color:#FFFFFF;border-radius:5px;}"));

    QString strSelectType;
    if(selectType == SelectType_Rect)
        strSelectType = "SelectType_Rect";
    else if(selectType == SelectType_Circle)
        strSelectType = "SelectType_Circle";
    else if(selectType == SelectType_Triangle)
        strSelectType = "SelectType_Triangle";
    else if(selectType == SelectType_Image)
        strSelectType = "SelectType_Image";

    qss.append(QString("CalendarItem{qproperty-showLunar:%1;}").arg(showLunar));
    qss.append(QString("CalendarItem{qproperty-bgImage:%1;}").arg(bgImage));
    qss.append(QString("CalendarItem{qproperty-selectType:%1;}").arg(strSelectType));
    qss.append(QString("CalendarItem{qproperty-borderColor:%1;}").arg(borderColor.name()));
    qss.append(QString("CalendarItem{qproperty-weekColor:%1;}").arg(weekColor.name()));
    qss.append(QString("CalendarItem{qproperty-superColor:%1;}").arg(superColor.name()));
    qss.append(QString("CalendarItem{qproperty-lunarColor:%1;}").arg(lunarColor.name()));
    qss.append(QString("CalendarItem{qproperty-currentTextColor:%1;}").arg(currentTextColor.name()));
    qss.append(QString("CalendarItem{qproperty-otherTextColor:%1;}").arg(otherTextColor.name()));
    qss.append(QString("CalendarItem{qproperty-selectTextColor:%1;}").arg(selectTextColor.name()));
    qss.append(QString("CalendarItem{qproperty-hoverTextColor:%1;}").arg(hoverTextColor.name()));
    qss.append(QString("CalendarItem{qproperty-currentLunarColor:%1;}").arg(currentLunarColor.name()));
    qss.append(QString("CalendarItem{qproperty-otherLunarColor:%1;}").arg(otherLunarColor.name()));
    qss.append(QString("CalendarItem{qproperty-selectLunarColor:%1;}").arg(selectLunarColor.name()));
    qss.append(QString("CalendarItem{qproperty-hoverLunarColor:%1;}").arg(hoverLunarColor.name()));
    qss.append(QString("CalendarItem{qproperty-currentBgColor:%1;}").arg(currentBgColor.name()));
    qss.append(QString("CalendarItem{qproperty-otherBgColor:%1;}").arg(otherBgColor.name()));
    qss.append(QString("CalendarItem{qproperty-selectBgColor:%1;}").arg(selectBgColor.name()));
    qss.append(QString("CalendarItem{qproperty-hoverBgColor:%1;}").arg(hoverBgColor.name()));

    setStyleSheet(qss.join(""));
}

void Calendar::initDate()
{
    int year = date.year();
    int month = date.month();
//    int day = date.day();

    btnClick = true;
    cboxYear->setCurrentIndex(cboxYear->findText(QString("%1年").arg(year)));
    cboxMonth->setCurrentIndex(cboxMonth->findText(QString("%1月").arg(month)));
    btnClick = false;

    int week = CalendarInfo::Instance()->getFirstDayOfWeek(year, month);
    int countday = CalendarInfo::Instance()->getMonthDays(year, month);
    int countDayPre = CalendarInfo::Instance()->getMonthDays(1==month?year-1:year, 1==month?12:month-1);

    int startPre, endPre, startNext, endNext, index, tempYear, tempMonth, tempDay;
    if(0==week)
    {
        startPre = 0;
        endPre = 7;
        startNext = 0;
        endNext = week + countday;
        endNext = 42 - (countday + 7);
    }
    else
    {
        startPre = 0;
        endPre = week;
        startNext = week + countday;
        endNext = 42;
    }

    tempYear = year;
    tempMonth = month - 1;
    if(tempMonth < 1)
    {
        tempYear--;
        tempMonth = 12;
    }

    for(int i=startPre; i<endPre; i++)
    {
        index = i;
        tempDay = countDayPre - endPre + i +1;
        QDate date(tempYear, tempMonth, tempDay);
        QString lunar = CalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay);
        dayItems.at(index)->setDate(date, lunar, CalendarItem::DayType_MonthPre);
    }

    tempYear = year;
    tempMonth = month+1;
    if(tempMonth > 12)
    {
        tempYear++;
        tempMonth = 1;
    }

    for(int i=startNext; i<endNext; i++)
    {
        index = 42 - endNext + i;
        tempDay = i - startNext + 1;

        QDate date(tempYear, tempMonth, tempDay);
        QString lunar = CalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay);
        dayItems.at(index)->setDate(date, lunar, CalendarItem::DayType_MonthNext);
    }

    tempYear = year;
    tempMonth = month;

    for(int i=week; i<(countday + week); i++)
    {
        index = (0==week?(i+7):i);
        tempDay = i - week + 1;
        QDate date(tempYear, tempMonth, tempDay);
        QString lunar = CalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay);
        if(0==(i%7) || 6==(i%7))
            dayItems.at(index)->setDate(date, lunar, CalendarItem::DayType_MonthCurrent);
        else
            dayItems.at(index)->setDate(date, lunar, CalendarItem::DayType_MonthCurrent);
    }
    dayChanged(this->date);
}

void Calendar::dayChanged(QDate date)
{
    int year = date.year();
    int month = date.month();
    int day = date.day();
    int week = CalendarInfo::Instance()->getFirstDayOfWeek(year, month);

    for(int i=0; i<42; i++)
    {
        int index = day + week - 1;
        if(week == 0)
        {
            index = day + 6;
        }

        dayItems.at(i)->setSelect(i == index);
    }

    emit clicked(date);
    emit selectionChanged();
}

void Calendar::showPreviousYear()
{
    int year = date.year();
    int month = date.month();
    int day = date.day();
    if(year == 1901)
        return ;
    year--;
    dateChanged(year, month, day);
}

void Calendar::showNextYear()
{
    int year = date.year();
    int month = date.month();
    int day = date.day();

    if(year >= 2099)
        return ;
    year++;
    dateChanged(year, month, day);
}

void Calendar::showPreviousMonth()
{
    int year = date.year();
    int month = date.month();
    int day = date.day();
    if(year <=1901 && month==1)
    {
        return ;
    }

    month--;
    if(month<1)
    {
        month = 12;
        year--;
    }
    dateChanged(year, month, day);
}

void Calendar::showNextMonth()
{
    int year = date.year();
    int month = date.month();
    int day = date.day();

    month++;
    if(month > 12)
    {
        month =  1;
        year++;
    }
    dateChanged(year, month, day);
}

void Calendar::showToday()
{
    date = QDate::currentDate();
    initDate();
    dayChanged(date);
}

void Calendar::yearChanged(QString a)
{
    if(btnClick)
        return ;

    int year = a.mid(0, a.length()-1).toInt();
    int month = date.month();
    int day = date.day();
    dateChanged(year, month, day);
}

void Calendar::monthChanges(QString a)
{
    if(btnClick)
        return ;

    int year = date.year();
    int month = a.mid(0, a.length()-1).toInt();
    int day = date.day();
    dateChanged(year, month, day);
}

void Calendar::dateChanged(int year, int month, int day)
{
    date.setDate(year, month, day>28?1:day);
    initDate();
}

void Calendar::setDate(const QDate &date)
{
    if(this->date != date)
    {
        this->date = date;
        initDate();
    }
}

void Calendar::setWeekTextColor(const QColor &weekTextColor)
{
    if(this->weekTextColor != weekTextColor)
    {
        this->weekTextColor = weekTextColor;
        initStyle();
    }
}

void Calendar::setWeekBgColor(const QColor &weekBgColor)
{
    if(this->weekBgColor != weekBgColor)
    {
        qDebug() << "setWeekBgColor = " << weekBgColor;
        this->weekBgColor = weekBgColor;
        initStyle();
    }
}

void Calendar::setShowLunar(bool showLunar)
{
    if(this->showLunar != showLunar)
    {
        this->showLunar = showLunar;
        initStyle();
        qDebug() << showLunar;
    }
}

void Calendar::setBgImage(const QString &bgImage)
{
    if(this->bgImage != bgImage)
    {
        this->bgImage = bgImage;
        initStyle();
    }
}

void Calendar::setSelectType(const SelectType &selectType)
{
    if(this->selectType != selectType)
    {
        this->selectType = selectType;
        initStyle();
    }
}

void Calendar::setBorderColor(const QColor &borderColor)
{
    if(this->borderColor != borderColor)
    {
        this->borderColor = borderColor;
        initStyle();
    }
}

void Calendar::setWeekColor(const QColor &weekColor)
{
    if(this->weekColor != weekColor)
    {
        this->weekColor = weekColor;
        initStyle();
    }
}

void Calendar::setLunarColor(const QColor &lunarColor)
{
    if(this->lunarColor != lunarColor)
    {
        this->lunarColor = lunarColor;
        initStyle();
    }
}

void Calendar::setCurrentTextColor(const QColor &currentTextColor)
{
    if(this->currentTextColor != currentTextColor)
    {
        this->currentTextColor = currentTextColor;
        initStyle();
    }
}

void Calendar::setHoverTextColor(const QColor &hoverTextColor)
{
    if(this->hoverTextColor != hoverTextColor)
    {
        this->hoverTextColor = hoverTextColor;
        initStyle();
    }
}

void Calendar::setOtherTextColor(const QColor &otherTextColor)
{
    if(this->otherTextColor != otherTextColor)
    {
        this->otherTextColor = otherTextColor;
        initStyle();
    }
}

void Calendar::setCurrentLunarColor(const QColor &currentLunarColor)
{
    if(this->currentLunarColor != currentLunarColor)
    {
        this->currentLunarColor = currentLunarColor;
        initStyle();
    }
}

void Calendar::setOtherLunarColor(const QColor &otherLunarColor)
{
    if(this->otherLunarColor == otherLunarColor)
    {
        this->otherLunarColor = otherLunarColor;
        initStyle();
    }
}

void Calendar::setSelectLunarColor(const QColor &selectLunarColor)
{
    if(this->selectLunarColor != selectLunarColor)
    {
        this->selectLunarColor = selectLunarColor;
        initStyle();
    }
}

void Calendar::setHoverLunarColor(const QColor &hoverLunarColor)
{
    if(this->hoverLunarColor != hoverLunarColor)
    {
        this->hoverLunarColor = hoverLunarColor;
        initStyle();
    }
}

void Calendar::setCurrentBgColor(const QColor &currentBgColor)
{
    if(this->currentBgColor != currentBgColor)
    {
        this->currentBgColor = currentBgColor;
        initStyle();
    }
}

void Calendar::setSelectBgColor(const QColor &selectBgColor)
{
    if(this->selectBgColor != selectBgColor)
    {
        this->selectBgColor = selectBgColor;
        initStyle();
    }
}

void Calendar::setHoverBgColor(const QColor &hoverBgColor)
{
    if(this->hoverBgColor != hoverBgColor)
    {
        this->hoverBgColor = hoverBgColor;
        initStyle();
    }
}

void Calendar::clicked(QDate date, CalendarItem::DayType dayType)
{
    if(CalendarItem::DayType_MonthPre == dayType)
    {
        showPreviousMonth();
    }
    else if(dayType == CalendarItem::DayType_MonthNext)
        showNextMonth();
    else
    {
        this->date = date;
        dayChanged(this->date);
    }
}

void Calendar::setCalendarStyle(const CalendarStyle &calendarStyle)
{
    if(this->calendarStyle != calendarStyle)
    {
        this->calendarStyle = calendarStyle;
        update();
    }
}

void Calendar::setWeekNameFormat(const WeekNameFormat &weekNameFormat)
{
    if (this->weekNameFormat != weekNameFormat) {
        this->weekNameFormat = weekNameFormat;

        QStringList listWeek;
        if (weekNameFormat == WeekNameFormat_Short) {
            listWeek << "日" << "一" << "二" << "三" << "四" << "五" << "六";
        } else if (weekNameFormat == WeekNameFormat_Normal) {
            listWeek << "周日" << "周一" << "周二" << "周三" << "周四" << "周五" << "周六";
        } else if (weekNameFormat == WeekNameFormat_Long) {
            listWeek << "星期天" << "星期一" << "星期二" << "星期三" << "星期四" << "星期五" << "星期六";
        } else if (weekNameFormat == WeekNameFormat_En) {
            listWeek << "Sun" << "Mon" << "Tue" << "Wed" << "Thu" << "Fri" << "Sat";
        }

        //逐个添加日期文字
        for (int i = 0; i < 7; i++) {
            labelWeeks.at(i)->setText(listWeek.at(i));
        }
    }
/*
    if(this->weekNameFormat != weekNameFormat)
    {
        this->weekNameFormat = weekNameFormat;
        update();
    }
 */
}

void Calendar::setSuperColor(const QColor &superColor)
{
    if(this->superColor != superColor)
    {
        this->superColor = superColor;
        update();
    }
}

void Calendar::setSelectTextColor(const QColor &selectTextColor)
{
    if(this->selectTextColor != selectTextColor)
    {
        this->selectTextColor = selectTextColor;
        update();
    }
}

void Calendar::setOtherBgColor(const QColor &otherBgColor)
{
    if(this->otherBgColor != otherBgColor)
    {
        this->otherBgColor = otherBgColor;
        update();
    }
}

/*
void Calendar::clicked(QDate date, CalendarItem::DayType dayType)
{
    if(CalendarItem::DayType_MonthPre == dayType)
        showPreviousMonth();
    else if(CalendarItem::DayType_MonthNext == dayType)
        showNextMonth();
    else
    {
        this->date = date;
        dayChanged(this->date);
    }
}
*/





















